package cn.lijiajia3515.cairo.security.web.authentication;

import cn.lijiajia3515.cairo.core.business.AuthBusiness;
import cn.lijiajia3515.cairo.core.business.Business;
import cn.lijiajia3515.cairo.core.business.DefaultBusiness;
import cn.lijiajia3515.cairo.core.result.error.ErrorBusinessResult;
import cn.lijiajia3515.cairo.http.converter.AbstractHttpMessageHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationManager;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

/**
 * 权限不足 处理器
 * <p>异常message 输出到 response</p>
 */
@Slf4j
public class CairoHttpMessageAccessDeniedHandler extends AbstractHttpMessageHandler implements AccessDeniedHandler {
	private static final ThrowableAnalyzer analyzer = new DefaultThrowableAnalyzer();

	public CairoHttpMessageAccessDeniedHandler(List<HttpMessageConverter<?>> converters) {
		super(converters, null);
	}

	public CairoHttpMessageAccessDeniedHandler(List<HttpMessageConverter<?>> converters, ContentNegotiationManager contentNegotiationManager) {
		super(converters, contentNegotiationManager);
	}

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
					   AccessDeniedException accessDeniedException) throws HttpMediaTypeNotAcceptableException, IOException {
		log.debug("authentication accessDenied ", accessDeniedException);
		HttpStatus httpStatus = HttpStatus.FORBIDDEN;
		Business business = AuthBusiness.Denied;

		if (accessDeniedException instanceof AuthorizationServiceException) {
			httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
			business = DefaultBusiness.Unknown;
		}

		response.setStatus(httpStatus.value());
		write(business, accessDeniedException, request, response);
	}



	public void write(Business business, AccessDeniedException exception, HttpServletRequest request, HttpServletResponse response) throws HttpMediaTypeNotAcceptableException, IOException {
		ErrorBusinessResult returnValue = ErrorBusinessResult.builder()
			.business(business)
			.exceptions(Arrays.asList(analyzer.determineCauseChain(exception))).build();
		writeWithMessageConverters(returnValue, new ServletServerHttpRequest(request), new ServletServerHttpResponse(response));
	}

}
